home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 June / EnigmA AMIGA RUN 08 (1996)(G.R. Edizioni)(IT)[!][issue 1996-06][EARSAN CD VII].iso / earcd / comm1 / mgplp378.lha / magplip / source / server.c < prev    next >
C/C++ Source or Header  |  1996-04-10  |  35KB  |  1,115 lines

  1. /*
  2. ** $VER: server.c 1.13 (29 Mar 1996)
  3. **
  4. ** magplip.device - Parallel Line Internet Protocol
  5. **
  6. ** Original code written by Oliver Wagner and Michael Balzer.
  7. **
  8. ** This version has been completely reworked by Marius Gröger, introducing
  9. ** slight protocol changes. The new source is a lot better organized and
  10. ** maintainable.
  11. **
  12. ** Additional changes and code cleanup by Jan Kratochvil and Martin Mares.
  13. ** The new source is significantly faster and yet better maintainable.
  14. **
  15. ** (C) Copyright 1993-1994 Oliver Wagner & Michael Balzer
  16. ** (C) Copyright 1995 Jan Kratochvil & Martin Mares
  17. ** (C) Copyright 1995-1996 Marius Gröger
  18. **     All Rights Reserved
  19. **
  20. ** $HISTORY:
  21. **
  22. ** 29 Mar 1996 : 001.014 :  changed copyright note
  23. ** 24 Feb 1996 : 001.013 :  added PRTRSEL data direction signal
  24. ** 30 Dec 1995 : 001.012 :  + dynamic allocation of only one frame buffer
  25. **                          PLIP_MAXMTU now 128k
  26. **                          + a bad MTU setting in ENV: will be
  27. **                          forced to PLIP_MAXMTU instead of PLIP_DEFMTU
  28. **                          + server task acknowledge now after calling
  29. **                          readargs to avoid inconsistencies
  30. ** 03 Sep 1995 : 001.011 :  hardware addressing nicer
  31. ** 30 Aug 1995 : 001.010 :  + support for timer-timed timeout :-)
  32. **                          + minor declaration related changes
  33. ** 20 Aug 1995 : 001.009 :  support for ASM xfer routines
  34. **                          removed obsolete CIA macros (mag/jk/mm)
  35. ** 29 Jul 1995 : 001.008 :  support for arbitration delay
  36. **                          symmetrical handling
  37. ** 26 Apr 1995 : 001.007 :  _very_ nasty bug would miss packets and get
  38. **                          the driver totally irritated
  39. ** 25 Apr 1995 : 001.006 :  now compiles with ANSI and STRICT
  40. **                          fixed bug with resource allocation
  41. ** 08 Mar 1995 : 001.005 :  write req. are now handled by device.c
  42. ** 06 Mar 1995 : 001.004 :  collision delay added
  43. ** 06 Mar 1995 : 001.003 :  hardware transmission errors are no longer retried
  44. **                          because this is any upper layers job
  45. ** 04 Mar 1995 : 001.002 :  event tracking *much* more conform to SANA-2
  46. ** 18 Feb 1995 : 001.001 :  startup now a bit nicer
  47. **                          using BASEPTR
  48. ** 12 Feb 1995 : 001.000 :  reworked original
  49. */
  50.  
  51. #define DEBUG 0
  52.  
  53. /*F*/ /* includes */
  54. #ifndef CLIB_EXEC_PROTOS_H
  55. #include <clib/exec_protos.h>
  56. #include <pragmas/exec_sysbase_pragmas.h>
  57. #endif
  58. #ifndef CLIB_DOS_PROTOS_H
  59. #include <clib/dos_protos.h>
  60. #include <pragmas/dos_pragmas.h>
  61. #endif
  62. #ifndef CLIB_CIA_PROTOS_H
  63. #include <clib/cia_protos.h>
  64. #include <pragmas/cia_pragmas.h>
  65. #endif
  66. #ifndef CLIB_MISC_PROTOS_H
  67. #include <clib/misc_protos.h>
  68. #include <pragmas/misc_pragmas.h>
  69. #endif
  70. #ifndef CLIB_TIME_PROTOS_H
  71. #include <clib/timer_protos.h>
  72. #include <pragmas/timer_pragmas.h>
  73. #endif
  74. #ifndef CLIB_UTILITY_PROTOS_H
  75. #include <clib/utility_protos.h>
  76. #include <pragmas/utility_pragmas.h>
  77. #endif
  78.  
  79. #ifndef EXEC_MEMORY_H
  80. #include <exec/memory.h>
  81. #endif
  82. #ifndef EXEC_INTERRUPTS_H
  83. #include <exec/interrupts.h>
  84. #endif
  85. #ifndef EXEC_DEVICES_H
  86. #include <exec/devices.h>
  87. #endif
  88. #ifndef EXEC_IO_H
  89. #include <exec/io.h>
  90. #endif
  91.  
  92. #ifndef DEVICES_SANA2_H
  93. #include <devices/sana2.h>
  94. #endif
  95.  
  96. #ifndef HARDWARE_CIA_H
  97. #include <hardware/cia.h>
  98. #endif
  99.  
  100. #ifndef RESOURCES_MISC_H
  101. #include <resources/misc.h>
  102. #endif
  103.  
  104. #ifndef _STRING_H
  105. #include <string.h>
  106. #endif
  107.  
  108. #ifndef __MAGPLIP_H
  109. #include "magplip.h"
  110. #endif
  111. #ifndef __DEBUG_H
  112. #include "debug.h"
  113. #endif
  114. #ifndef __COMPILER_H
  115. #include "compiler.h"
  116. #endif
  117. /*E*/
  118.  
  119. /*F*/ /* defines, types and enums */
  120.  
  121.    /*
  122.    ** return codes for arbitratedwrite()
  123.    */
  124. typedef enum { AW_OK, AW_ABORTED, AW_BUFFER_ERROR, AW_ERROR } AW_RESULT;
  125.  
  126.    /* return val, cut to min or max if exceeding range */
  127. #define BOUNDS(val, min, max) ((val) <= (max) ? ((val) >= (min) ? (val) :\
  128.                                                          (min)) : (max))
  129.  
  130. /*E*/
  131. /*F*/ /* imports */
  132.    /* external functions */
  133. GLOBAL VOID dotracktype(BASEPTR, ULONG type, ULONG ps, ULONG pr, ULONG bs, ULONG br, ULONG pd);
  134. GLOBAL VOID DevTermIO(BASEPTR, struct IOSana2Req *ios2);
  135. GLOBAL USHORT ASM CRC16(REG(a0) UBYTE *, REG(d0) SHORT);
  136. GLOBAL BOOL ASM hwsend(REG(a0) BASEPTR);
  137. GLOBAL BOOL ASM hwrecv(REG(a0) BASEPTR);
  138. GLOBAL VOID ASM interrupt(REG(a1) BASEPTR);
  139.  
  140.    /* amiga.lib provides for these symbols */
  141. GLOBAL FAR volatile struct CIA ciaa,ciab;
  142. /*E*/
  143. /*F*/ /* exports */
  144. PUBLIC VOID SAVEDS ServerTask(void);
  145. /*E*/
  146. /*F*/ /* private */
  147. PRIVATE struct PLIPBase *startup(void);
  148. PRIVATE REGARGS VOID DoEvent(BASEPTR, long event);
  149. PRIVATE VOID readargs(BASEPTR);
  150. PRIVATE BOOL init(BASEPTR);
  151. PRIVATE BOOL hwattach(BASEPTR);
  152. PRIVATE VOID hwdetach(BASEPTR);
  153. PRIVATE REGARGS BOOL goonline(BASEPTR);
  154. PRIVATE REGARGS VOID gooffline(BASEPTR);
  155. PRIVATE REGARGS AW_RESULT arbitratedwrite(BASEPTR, struct IOSana2Req *ios2);
  156. PRIVATE REGARGS VOID dowritereqs(BASEPTR);
  157. PRIVATE REGARGS VOID doreadreqs(BASEPTR);
  158. PRIVATE REGARGS VOID dos2reqs(BASEPTR);
  159. /*E*/
  160.  
  161. /*F*/ /* CIA access macros & functions */
  162.  
  163. #define CLEARINT        SetICR(CIAABase, CIAICRF_FLG)
  164. #define DISABLEINT      AbleICR(CIAABase, CIAICRF_FLG)
  165. #define ENABLEINT       AbleICR(CIAABase, CIAICRF_FLG | CIAICRF_SETCLR)
  166.  
  167. #define SETCIAOUTPUT    ciab.ciapra |= CIAF_PRTRSEL; ciaa.ciaddrb = 0xFF
  168. #define SETCIAINPUT     ciab.ciapra &= ~CIAF_PRTRSEL; ciaa.ciaddrb = 0x00
  169. #define PARINIT(b)      SETCIAINPUT;                                       \
  170.                         ciab.ciaddra &= ~((b)->pb_HandshakeMask[HS_LINE]); \
  171.                         ciab.ciaddra |= (b)->pb_HandshakeMask[HS_REQUEST]
  172.  
  173. #define TESTLINE(b)     (ciab.ciapra & (b)->pb_HandshakeMask[HS_LINE])
  174. #define SETREQUEST(b)   ciab.ciapra |= (b)->pb_HandshakeMask[HS_REQUEST]
  175. #define CLEARREQUEST(b) ciab.ciapra &= ~((b)->pb_HandshakeMask[HS_REQUEST])
  176.  
  177. /*E*/
  178.  
  179.    /*
  180.    ** functions to gain/release hardware, initialise communication
  181.    ** and for xmission timeout handling
  182.    */
  183. /*F*/ PRIVATE BOOL hwattach(BASEPTR)
  184. {
  185.    BOOL rc = FALSE;
  186.  
  187.    d(("entered\n"));
  188.  
  189.    if (MiscBase = OpenResource("misc.resource"))
  190.    {
  191.       if (CIAABase = OpenResource("ciaa.resource"))
  192.       {
  193.          CiaBase = CIAABase;
  194.  
  195.          d(("ciabase is %lx\n",CiaBase));
  196.  
  197.          /* obtain exclusive access to the parallel hardware */
  198.          if (!AllocMiscResource(MR_PARALLELPORT, pb->pb_DevNode.lib_Node.ln_Name))
  199.          {
  200.             pb->pb_AllocFlags |= 1;
  201.             if (!AllocMiscResource(MR_PARALLELBITS, pb->pb_DevNode.lib_Node.ln_Name))
  202.             {
  203.                pb->pb_AllocFlags |= 2;
  204.  
  205.                /* Add our interrupt to handle CIAICRB_FLG.
  206.                ** This is also cia.resource means of granting exclusive
  207.                ** access to the related registers in the CIAs.
  208.                */
  209.                pb->pb_Interrupt.is_Node.ln_Type = NT_INTERRUPT;
  210.                pb->pb_Interrupt.is_Node.ln_Pri  = 127;
  211.                pb->pb_Interrupt.is_Node.ln_Name = SERVERTASKNAME;
  212.                pb->pb_Interrupt.is_Data         = (APTR)pb;
  213.                pb->pb_Interrupt.is_Code         = (VOID (*)())&interrupt;
  214.  
  215.                /* We must Disable() bcos there could be an interrupt already
  216.                ** waiting for us. We may, however, not Able/SetICR() before
  217.                ** we have access!
  218.                */
  219.                Disable();
  220.                if (!AddICRVector(CIAABase, CIAICRB_FLG, &pb->pb_Interrupt))
  221.                {
  222.                   DISABLEINT;                       /* this is what I meant */
  223.                   rc = TRUE;
  224.                }
  225.                Enable();
  226.  
  227.                if (rc)
  228.                {
  229.                   pb->pb_AllocFlags |= 4;
  230.                   PARINIT(pb);    /* cia to input, handshake in/out setting */
  231.                   CLEARREQUEST(pb);                /* setup handshake lines */
  232.                   CLEARINT;                         /* clear this interrupt */
  233.                   ENABLEINT;                            /* allow interrupts */
  234.                }
  235.  
  236.             }
  237.             else
  238.                d(("no parallelbits\n"));
  239.          }
  240.          else
  241.             d(("no parallelport\n"));
  242.       }
  243.       else
  244.          d(("no misc resource\n"));
  245.    }
  246.    else
  247.       d(("no misc resource\n"));
  248.  
  249.    return rc;
  250. }
  251. /*E*/
  252. /*F*/ PRIVATE VOID hwdetach(BASEPTR)
  253. {
  254.    if (pb->pb_AllocFlags & 4)
  255.    {
  256.       DISABLEINT;
  257.       CLEARINT;
  258.       RemICRVector(CIAABase, CIAICRB_FLG, &pb->pb_Interrupt);
  259.    }
  260.  
  261.    if (pb->pb_AllocFlags & 2) FreeMiscResource(MR_PARALLELBITS);
  262.  
  263.    if (pb->pb_AllocFlags & 1) FreeMiscResource(MR_PARALLELPORT);
  264.  
  265.    pb->pb_AllocFlags = 0;
  266. }
  267. /*E*/
  268. /*F*/ PRIVATE ULONG ASM SAVEDS exceptcode(REG(d0) ULONG sigmask, REG(a1) BASEPTR)
  269. {
  270.    /*extern void KPrintF(char *,...);
  271.    KPrintF("exceptcode\n");*/
  272.  
  273.    /* remove the I/O Block from the port */
  274.    WaitIO((struct IORequest*)&pb->pb_TimeoutReq);
  275.  
  276.    /* this tells the xfer routines to cease polling */
  277.    pb->pb_TimeoutSet = 0xff;
  278.  
  279.    return sigmask;            /* re-enable the signal */
  280. }
  281. /*E*/
  282.  
  283.    /*
  284.    ** functions to go online/offline
  285.    */
  286. /*F*/ PRIVATE REGARGS VOID rejectpackets(BASEPTR)
  287. {
  288.    struct IOSana2Req *ios2;
  289.  
  290.    ObtainSemaphore(&pb->pb_WriteListSem);
  291.    while(ios2 = (struct IOSana2Req *)RemHead((struct List*)&pb->pb_WriteList))
  292.    {
  293.       ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
  294.       ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
  295.       DevTermIO(pb,ios2);
  296.    }
  297.    ReleaseSemaphore(&pb->pb_WriteListSem);
  298.  
  299.    ObtainSemaphore(&pb->pb_ReadListSem);
  300.    while(ios2 = (struct IOSana2Req *)RemHead((struct List*)&pb->pb_ReadList))
  301.    {
  302.       ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
  303.       ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
  304.       DevTermIO(pb,ios2);
  305.    }
  306.    ReleaseSemaphore(&pb->pb_ReadListSem);
  307.  
  308.    ObtainSemaphore(&pb->pb_ReadOrphanListSem);
  309.    while(ios2 = (struct IOSana2Req *)RemHead((struct List*)&pb->pb_ReadOrphanList))
  310.    {
  311.       ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
  312.       ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
  313.       DevTermIO(pb,ios2);
  314.    }
  315.    ReleaseSemaphore(&pb->pb_ReadOrphanListSem);
  316. }
  317. /*E*/
  318. /*F*/ PRIVATE REGARGS BOOL goonline(BASEPTR)
  319. {
  320.    BOOL rc = FALSE;
  321.  
  322.    d(("trying to go online\n"));
  323.  
  324.    if (pb->pb_Flags & (PLIPF_OFFLINE | PLIPF_NOTCONFIGURED))
  325.    {
  326.       if (!hwattach(pb))
  327.       {
  328.          d(("error going online\n"));
  329.       }
  330.       else
  331.       {
  332.          GetSysTime(&pb->pb_DevStats.LastStart);
  333.          pb->pb_Flags &= ~(PLIPF_OFFLINE | PLIPF_NOTCONFIGURED);
  334.          DoEvent(pb, S2EVENT_ONLINE);
  335.          rc = TRUE;
  336.          d(("i'm now online!\n"));
  337.       }
  338.    }
  339.  
  340.    return rc;
  341. }
  342. /*E*/
  343. /*F*/ PRIVATE REGARGS VOID gooffline(BASEPTR)
  344. {
  345.    if (!(pb->pb_Flags & (PLIPF_OFFLINE | PLIPF_NOTCONFIGURED)))
  346.    {
  347.       hwdetach(pb);
  348.  
  349.       pb->pb_Flags |= PLIPF_OFFLINE;
  350.  
  351.       DoEvent(pb, S2EVENT_OFFLINE);
  352.    }
  353.    d(("ok!\n"));
  354. }
  355. /*E*/
  356.  
  357.    /*
  358.    ** SANA-2 Event management
  359.    */
  360. /*F*/ PRIVATE REGARGS VOID DoEvent(BASEPTR, long event)
  361. {
  362.    struct IOSana2Req *ior, *ior2;
  363.  
  364.    d(("event is %lx\n",event));
  365.  
  366.    ObtainSemaphore(&pb->pb_EventListSem );
  367.    
  368.    for(ior = (struct IOSana2Req *) pb->pb_EventList.lh_Head;
  369.        ior2 = (struct IOSana2Req *) ior->ios2_Req.io_Message.mn_Node.ln_Succ;
  370.        ior = ior2 )
  371.    {
  372.       if (ior->ios2_WireError & event)
  373.       {
  374.          Remove((struct Node*)ior);
  375.          DevTermIO(pb, ior);
  376.       }
  377.    }
  378.    
  379.    ReleaseSemaphore(&pb->pb_EventListSem );
  380. }
  381. /*E*/
  382.  
  383.    /*
  384.    ** writing packets
  385.    */
  386. /*F*/ PRIVATE REGARGS AW_RESULT arbitratedwrite(BASEPTR, struct IOSana2Req *ios2)
  387. {
  388.    BOOL having_line;
  389.    AW_RESULT rc;
  390.    struct PLIPFrame *frame = pb->pb_Frame;
  391.  
  392.    /*
  393.    ** Arbitration
  394.    ** ===========================================================
  395.    **
  396.    ** Pseudo code of the arbitration:
  397.    **
  398.    **  if LINE is high (other side is ready to receive) then
  399.    **     set REQUEST high (tell the other side we're ready to send)
  400.    **     if LINE is high (other side is still ready to receive) then
  401.    **        we have the line, do transfer
  402.    **     reset REQUEST to low (tell other side we're ready to receive)
  403.    **
  404.    **    AW_OK             if we could transmit all the data correctly
  405.    **    AW_BUFF_ERROR     if the BufferManagement callback failed
  406.    **    AW_ERROR          if we got the line, but the actual transfer
  407.    **                      failed, perhaps due to a timeout
  408.    **    AW_ABORT          if we couldn't get the line
  409.    */
  410.  
  411.    having_line = FALSE;
  412.  
  413.    if (!TESTLINE(pb))                               /* is the line free ? */
  414.    {
  415.       SETREQUEST(pb);                     /* indicate our request to send */
  416.       
  417. #if 0
  418.       I have removed again the ARBITRATIONDELAY feature, although I am not
  419.       really sure if this is a good thing. Anyway I didn't experience
  420.       any more those nasty line errors, that initially made me implementing
  421.       this. For now I've left the code here to let you play with it. Please
  422.       report any comments concerning this.
  423.  
  424.       In fact the arbitration leaves a small door for undetected, real
  425.       collisision, as the request lines are used for handshake during the
  426.       transmission process. The CLEARREQUEST after NOT getting the line
  427.       could be misinterpreted by the other side as the first handshake. Up
  428.       to now I couldn't conceive a satisfying solution for this.
  429.  
  430.       if (pb->pb_ArbitrationDelay > 0)
  431.       {
  432.          pb->pb_CollReq.tr_time.tv_secs    = 0;
  433.          pb->pb_CollReq.tr_time.tv_micro   = pb->pb_ArbitrationDelay;
  434.          pb->pb_CollReq.tr_node.io_Command = TR_ADDREQUEST;
  435.          DoIO((struct IORequest*)&pb->pb_CollReq);
  436.       }
  437. #endif
  438.  
  439.       if (!TESTLINE(pb))                      /* is the line still free ? */
  440.          having_line = TRUE;
  441.       else
  442.       {
  443.          if (!(pb->pb_Flags & PLIPF_RECEIVING))
  444.             CLEARREQUEST(pb);                         /* reset line state */
  445.          d2(("couldn't get the line-1\n"));
  446.       }
  447.    }
  448.    else d2(("couldn't get the line-2\n"));
  449.  
  450.    if (having_line)
  451.    {
  452.       struct BufferManagement *bm;
  453.  
  454.       if (!(pb->pb_Flags & PLIPF_RECEIVING))
  455.       {
  456.          d(("having line for: type %08lx, size %ld\n",ios2->ios2_PacketType,
  457.                                                       ios2->ios2_DataLength));
  458.  
  459.          frame->pf_Type = ios2->ios2_PacketType;
  460.          frame->pf_Size = ios2->ios2_DataLength + PKTFRAMESIZE_2;
  461.  
  462.          bm = (struct BufferManagement *)ios2->ios2_BufferManagement;
  463.  
  464.          if (!(*bm->bm_CopyFromBuffer)((UBYTE*)(frame+1),
  465.                                      ios2->ios2_Data, ios2->ios2_DataLength))
  466.          {
  467.             rc = AW_BUFFER_ERROR;
  468.             CLEARREQUEST(pb);                         /* reset line state */
  469.          }
  470.          else
  471.          {
  472.             /* wait until I/O block is safe to be reused */
  473.             while(!pb->pb_TimeoutSet) Delay(1L);
  474.             pb->pb_TimeoutReq.tr_time.tv_secs = 0;
  475.             pb->pb_TimeoutReq.tr_time.tv_micro = pb->pb_Timeout;
  476.             pb->pb_TimeoutSet = 0;
  477.             SendIO((struct IORequest*)&pb->pb_TimeoutReq);
  478.             rc = hwsend(pb) ? AW_OK : AW_ERROR;
  479.             AbortIO((struct IORequest*)&pb->pb_TimeoutReq);
  480.          }
  481.       }
  482.       else
  483.       {
  484.          d4(("arbitration error!\n"));
  485.          rc = AW_ABORTED;
  486.       }
  487.    }
  488.    else
  489.       rc = AW_ABORTED;
  490.  
  491.    return rc;
  492. }
  493. /*E*/
  494. /*F*/ PRIVATE REGARGS VOID dowritereqs(BASEPTR)
  495. {
  496.    struct IOSana2Req *currentwrite, *nextwrite;
  497.    AW_RESULT code;
  498.  
  499.    ObtainSemaphore(&pb->pb_WriteListSem);
  500.  
  501.    for(currentwrite = (struct IOSana2Req *)pb->pb_WriteList.lh_Head;
  502.        nextwrite = (struct IOSana2Req *) currentwrite->ios2_Req.io_Message.mn_Node.ln_Succ;
  503.        currentwrite = nextwrite )
  504.    {
  505.       if (pb->pb_Flags & PLIPF_RECEIVING)
  506.       {
  507.          d(("incoming data!"));
  508.          break;
  509.       }
  510.  
  511.       code = arbitratedwrite(pb, currentwrite);
  512.  
  513.       if (code == AW_ABORTED)                         /* arbitration failed */
  514.       {
  515.          pb->pb_Flags |= PLIPF_COLLISION;
  516.          d(("couldn't get the line, trying again later\n"));
  517.          pb->pb_SpecialStats[S2SS_COLLISIONS].Count++;
  518.          d(("pb->pb_SpecialStats[S2SS_COLLISIONS].Count = %ld\n",pb->pb_SpecialStats[S2SS_COLLISIONS].Count));
  519.          if ((currentwrite->ios2_Req.io_Error++) > pb->pb_Retries)
  520.          {
  521.             pb->pb_SpecialStats[S2SS_TXERRORS].Count++;
  522.             d(("pb->pb_SpecialStats[S2SS_TXERRORS].Count = %ld\n",pb->pb_SpecialStats[S2SS_TXERRORS].Count));
  523.             currentwrite->ios2_Req.io_Error = S2ERR_TX_FAILURE;
  524.             currentwrite->ios2_WireError = S2WERR_TOO_MANY_RETIRES;
  525.             Remove((struct Node*)currentwrite);
  526.             DevTermIO(pb, currentwrite);
  527.          }
  528.          break;
  529.       }
  530.       else if (code == AW_BUFFER_ERROR)  /* BufferManagement callback error */
  531.       {
  532.          d(("buffer error\n"));
  533.          DoEvent(pb, S2EVENT_ERROR | S2EVENT_BUFF | S2EVENT_SOFTWARE);
  534.          pb->pb_SpecialStats[S2SS_TXERRORS].Count++;
  535.          d(("pb->pb_SpecialStats[S2SS_TXERRORS].Count = %ld\n",pb->pb_SpecialStats[S2SS_TXERRORS].Count));
  536.          currentwrite->ios2_Req.io_Error = S2ERR_SOFTWARE;
  537.          currentwrite->ios2_WireError = S2WERR_BUFF_ERROR;
  538.          Remove((struct Node*)currentwrite);
  539.          DevTermIO(pb, currentwrite);
  540.       }
  541.       else if (code == AW_ERROR)
  542.       {
  543.          /*
  544.          ** this is a real line error, upper levels (e.g. Internet TCP) have
  545.          ** to care for reliability!
  546.          */
  547.          d(("error while transmitting packet\n"));
  548.          DoEvent(pb, S2EVENT_ERROR | S2EVENT_TX | S2EVENT_HARDWARE);
  549.          pb->pb_SpecialStats[S2SS_TXERRORS].Count++;
  550.          d(("pb->pb_SpecialStats[S2SS_TXERRORS].Count = %ld\n",pb->pb_SpecialStats[S2SS_TXERRORS].Count));
  551.          currentwrite->ios2_Req.io_Error = S2ERR_TX_FAILURE;
  552.          currentwrite->ios2_WireError = S2WERR_GENERIC_ERROR;
  553.          Remove((struct Node*)currentwrite);
  554.          DevTermIO(pb, currentwrite);
  555.       }
  556.       else /*if (code == AW_OK)*/                             /* well done! */
  557.       {
  558.          d(("packet transmitted successfully\n"));
  559.          pb->pb_DevStats.PacketsSent++;
  560.          dotracktype(pb, pb->pb_Frame->pf_Type, 1, 0, currentwrite->ios2_DataLength, 0, 0);
  561.          currentwrite->ios2_Req.io_Error = S2ERR_NO_ERROR;
  562.          currentwrite->ios2_WireError = S2WERR_GENERIC_ERROR;
  563.          Remove((struct Node*)currentwrite);
  564.          DevTermIO(pb, currentwrite);
  565.       }
  566.    }
  567.  
  568.    ReleaseSemaphore(&pb->pb_WriteListSem);
  569. }
  570. /*E*/
  571.  
  572.    /*
  573.    ** reading packets
  574.    */
  575. /*F*/ PRIVATE REGARGS VOID doreadreqs(BASEPTR)
  576. {
  577.    LONG datasize;
  578.    struct IOSana2Req *got;
  579.    ULONG pkttyp;
  580.    struct BufferManagement *bm;
  581.    BOOL rv;
  582.    struct PLIPFrame *frame = pb->pb_Frame;
  583.  
  584.    /* wait until I/O block is safe to be reused */
  585.    while(!pb->pb_TimeoutSet) Delay(1L);
  586.    pb->pb_TimeoutReq.tr_time.tv_secs    = 0;
  587.    pb->pb_TimeoutReq.tr_time.tv_micro   = pb->pb_Timeout;
  588.    pb->pb_TimeoutSet = 0;
  589.    SendIO((struct IORequest*)&pb->pb_TimeoutReq);
  590.    rv = hwrecv(pb);
  591.    AbortIO((struct IORequest*)&pb->pb_TimeoutReq);
  592.  
  593.    if (rv)
  594.    {
  595.       pb->pb_DevStats.PacketsReceived++;
  596.  
  597.       datasize = frame->pf_Size - PKTFRAMESIZE_2;
  598.  
  599.       dotracktype(pb, pkttyp = frame->pf_Type, 0, 1, 0, datasize, 0);
  600.  
  601.       d(("packet %08lx, size %ld received\n",pkttyp,datasize));
  602.  
  603.       ObtainSemaphore(&pb->pb_ReadListSem);
  604.  
  605.          /* traverse the list of read-requests */
  606.       for(got = (struct IOSana2Req *)pb->pb_ReadList.lh_Head;
  607.           got->ios2_Req.io_Message.mn_Node.ln_Succ;
  608.           got = (struct IOSana2Req *)got->ios2_Req.io_Message.mn_Node.ln_Succ )
  609.       {
  610.             /* check if this one requests for the new packet we got */
  611.          if (got->ios2_PacketType == pkttyp )
  612.          {
  613.             Remove((struct Node*)got);
  614.  
  615.             bm = (struct BufferManagement *)got->ios2_BufferManagement;
  616.  
  617.             if (!(*bm->bm_CopyToBuffer)(got->ios2_Data, (UBYTE*)(frame+1), datasize))
  618.             {
  619.                d(("CopyToBuffer: error\n"));
  620.                got->ios2_Req.io_Error = S2ERR_SOFTWARE;
  621.                got->ios2_WireError = S2WERR_BUFF_ERROR;
  622.                DoEvent(pb, S2EVENT_ERROR | S2EVENT_BUFF | S2EVENT_SOFTWARE);
  623.             }
  624.             else
  625.             {
  626.                got->ios2_Req.io_Error = got->ios2_WireError = 0;
  627.             }
  628.  
  629.             got->ios2_Req.io_Flags = 0;
  630.             memcpy(got->ios2_SrcAddr, pb->pb_SrcAddr, PLIP_ADDRFIELDSIZE);
  631.             memcpy(got->ios2_DstAddr, pb->pb_DstAddr, PLIP_ADDRFIELDSIZE);
  632.             got->ios2_DataLength = datasize;
  633.  
  634.             d(("packet received, satisfying S2Request\n"));
  635.             DevTermIO(pb, got);
  636.             got = NULL;
  637.             break;
  638.          }
  639.       }
  640.  
  641.       ReleaseSemaphore(&pb->pb_ReadListSem);
  642.    }
  643.    else
  644.    {     /* something went wrong during receipt */
  645.       DoEvent(pb, S2EVENT_HARDWARE | S2EVENT_ERROR | S2EVENT_RX);
  646.       got = NULL;
  647.       pb->pb_DevStats.BadData++;
  648.    }
  649.  
  650.       /* If no one wanted this packet explicitely, there is one chance
  651.       ** left: somebody waiting for orphaned packets. If this fails, too,
  652.       ** we will drop it.
  653.       */
  654.    if (got)
  655.    {
  656.       d(("unknown packet\n"));
  657.  
  658.       pb->pb_DevStats.UnknownTypesReceived++;
  659.       
  660.       ObtainSemaphore(&pb->pb_ReadOrphanListSem);
  661.       got = (struct IOSana2Req *)RemHead((struct List*)&pb->pb_ReadOrphanList);
  662.       ReleaseSemaphore(&pb->pb_ReadOrphanListSem);
  663.  
  664.       if (got)
  665.       {
  666.          bm = (struct BufferManagement *)got->ios2_BufferManagement;
  667.          if (!(*bm->bm_CopyToBuffer)(got->ios2_Data, (UBYTE*)(frame+1), datasize))
  668.          {
  669.             got->ios2_Req.io_Error = S2ERR_SOFTWARE;
  670.             got->ios2_WireError = S2WERR_BUFF_ERROR;
  671.          }
  672.          else
  673.          {
  674.             got->ios2_Req.io_Error = got->ios2_WireError = 0;
  675.          }
  676.          
  677.          got->ios2_Req.io_Flags = 0;
  678.          memcpy(got->ios2_SrcAddr, pb->pb_SrcAddr, PLIP_ADDRFIELDSIZE);
  679.          memcpy(got->ios2_DstAddr, pb->pb_DstAddr, PLIP_ADDRFIELDSIZE);
  680.          got->ios2_DataLength = datasize;
  681.  
  682.          d(("orphan read\n"));
  683.  
  684.          DevTermIO(pb, got);
  685.       }
  686.       else
  687.       {
  688.          dotracktype(pb, pkttyp, 0, 0, 0, 0, 1);
  689.          d(("packet thrown away...\n"));
  690.       }
  691.    }
  692. }
  693. /*E*/
  694.  
  695.    /*
  696.    ** 2nd level device command dispatcher (~SANA2IOF_QUICK)
  697.    */
  698. /*F*/ PRIVATE REGARGS VOID dos2reqs(BASEPTR)
  699. {
  700.    struct IOSana2Req *ios2;
  701.  
  702.    /*
  703.    ** Every pending IO message will be GetMsg()'ed and processed. At the
  704.    ** end of the loop it will be DevTermIO()'ed back to the sender,
  705.    ** _but_only_if_ it is non-NULL. In such cases the message has been
  706.    ** put in a separate queue to be DevTermIO()'ed later (i.e. CMD_WRITEs
  707.    ** and similar stuff).
  708.    ** You find the same mimique in the 1st level dispatcher (device.c)
  709.    */
  710.    while(ios2 = (struct IOSana2Req *)GetMsg(pb->pb_ServerPort))
  711.    {
  712.       if (pb->pb_Flags & PLIPF_RECEIVING)
  713.       {
  714.          d(("incoming data!"));
  715.          break;
  716.       }
  717.  
  718.       d(("sana2req %ld from serverport\n", ios2->ios2_Req.io_Command));
  719.  
  720.       switch (ios2->ios2_Req.io_Command)
  721.       {
  722.          case S2_ONLINE:
  723.             if (!goonline(pb))
  724.             {
  725.                ios2->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
  726.                ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
  727.             }
  728.          break;
  729.  
  730.          case S2_OFFLINE:
  731.             gooffline(pb);
  732.             rejectpackets(pb); /* reject all pending requests */
  733.          break;
  734.  
  735.          case S2_CONFIGINTERFACE:
  736.             if (pb->pb_Flags & PLIPF_NOTCONFIGURED)
  737.             {
  738.                memcpy(ios2->ios2_SrcAddr, pb->pb_SrcAddr, PLIP_ADDRFIELDSIZE);
  739.                memcpy(ios2->ios2_DstAddr, pb->pb_DstAddr, PLIP_ADDRFIELDSIZE);
  740.                
  741.                if (!goonline(pb))
  742.                {
  743.                   ios2->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
  744.                   ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
  745.                }
  746.             }
  747.             else
  748.             {
  749.                ios2->ios2_Req.io_Error = S2ERR_BAD_STATE;
  750.                ios2->ios2_WireError = S2WERR_IS_CONFIGURED;
  751.             }
  752.          break;
  753.       }
  754.  
  755.       if (ios2) DevTermIO(pb,ios2);
  756.    }
  757. }
  758. /*E*/
  759.  
  760.    /*
  761.    ** startup,initialisation and termination functions
  762.    */
  763. /*F*/ PRIVATE struct PLIPBase *startup(void)
  764. {
  765.    struct ServerStartup *ss;
  766.    struct Process *we;
  767.    struct PLIPBase *base;
  768.    LOCALSYSBASE;
  769.  
  770.    we = (struct Process*)FindTask(NULL);
  771.  
  772.    d(("waiting for startup msg...\n"));
  773.    WaitPort(&we->pr_MsgPort);
  774.    ss = (struct ServerStartup *)GetMsg(&we->pr_MsgPort);
  775.    base = ss->ss_PLIPBase;
  776.    base->pb_Startup = ss;
  777.    d(("go startup msg at %lx, PLIPBase is %lx\n", ss, ss->ss_PLIPBase));
  778.  
  779.    /* we will keep the startup message, to inform mother if we
  780.    ** really could come up or if we failed to obtain some
  781.    ** resource.
  782.    */
  783.    return base;
  784. }
  785. /*E*/
  786. /*F*/ PRIVATE VOID readargs(BASEPTR)
  787. {
  788.    struct RDArgs *rda;
  789.    struct PLIPConfig args = { 0 };
  790.    BPTR plipvar, oldinput;
  791.  
  792.    d(("entered\n"));
  793.  
  794.    if (plipvar = Open(CONFIGFILE, MODE_OLDFILE))
  795.    {
  796.       oldinput = SelectInput(plipvar);
  797.       
  798.       rda = ReadArgs(TEMPLATE , (LONG *)&args, NULL);
  799.       
  800.       if(rda)
  801.       {
  802.          if (args.timeout)
  803.             pb->pb_Timeout =
  804.                   BOUNDS(*args.timeout, PLIP_MINTIMEOUT, PLIP_MAXTIMEOUT);
  805.  
  806.          if (args.priority)
  807.             SetTaskPri((struct Task*)pb->pb_Server,
  808.                   BOUNDS(*args.priority, PLIP_MINPRIORITY, PLIP_MAXPRIORITY));
  809.  
  810.          if (args.mtu)
  811.             pb->pb_MTU = BOUNDS(*args.mtu, PLIP_MINMTU, PLIP_MAXMTU);
  812.  
  813.          if (args.bps)
  814.             pb->pb_ReportBPS = BOUNDS(*args.bps, PLIP_MINBPS, PLIP_MAXBPS);
  815.  
  816.          if (args.retries)
  817.             pb->pb_Retries =
  818.                      BOUNDS(*args.retries, PLIP_MINRETRIES, PLIP_MAXRETRIES);
  819.  
  820.          if (args.sendcrc)
  821.             pb->pb_Flags |= PLIPF_SENDCRC;
  822.           else
  823.             pb->pb_Flags &= ~PLIPF_SENDCRC;
  824.  
  825.          if (args.collisiondelay)
  826.             pb->pb_CollisionDelay =
  827.                BOUNDS(*args.collisiondelay, PLIP_MINCOLLISIONDELAY,
  828.                                             PLIP_MAXCOLLISIONDELAY);
  829.          else
  830.             pb->pb_CollisionDelay = PLIP_DEFDELAY + (pb->pb_Unit ?
  831.                                                   PLIP_DELAYDIFF : 0);
  832.  
  833.          if (args.arbitrationdelay)
  834.             pb->pb_ArbitrationDelay =
  835.                BOUNDS(*args.collisiondelay, PLIP_MINARBITRATIONDELAY,
  836.                                             PLIP_MAXARBITRATIONDELAY);
  837.          else
  838.             pb->pb_ArbitrationDelay = PLIP_DEFARBITRATIONDELAY;
  839.  
  840.          if (args.nospecialstats)
  841.             pb->pb_ExtFlags |= PLIPEF_NOSPECIALSTATS;
  842.  
  843.          FreeArgs(rda);
  844.       }
  845.  
  846.       Close(SelectInput(oldinput));
  847.    }
  848.  
  849.    d(("timeout %ld, pri %ld, mtu %ld, bps %ld, retries %ld, flags %08lx, delay %ld\n",
  850.       pb->pb_Timeout, (LONG)pb->pb_Server->pr_Task.tc_Node.ln_Pri, pb->pb_MTU, pb->pb_ReportBPS, pb->pb_Retries,
  851.       pb->pb_Flags, pb->pb_CollisionDelay));
  852.  
  853.    d(("left\n"));
  854.  
  855. }
  856. /*E*/
  857. /*F*/ PRIVATE BOOL init(BASEPTR)
  858. {
  859.    BOOL rc = FALSE;
  860.    ULONG sigmask;
  861.  
  862.    if ((pb->pb_IntSig = AllocSignal(-1)) != -1)
  863.    {
  864.       pb->pb_IntSigMask = 1L << pb->pb_IntSig;
  865.    
  866.       if ((pb->pb_ServerPort = CreateMsgPort()))
  867.       {
  868.          if ((pb->pb_CollPort = CreateMsgPort()))
  869.          {
  870.             if ((pb->pb_TimeoutPort = CreateMsgPort()))
  871.             {
  872.                /* save old exception setup */
  873.                pb->pb_OldExcept = SetExcept(0, 0xffffffff); /* turn'em off */
  874.                pb->pb_OldExceptCode = pb->pb_Server->pr_Task.tc_ExceptCode;
  875.                pb->pb_OldExceptData = pb->pb_Server->pr_Task.tc_ExceptData;
  876.  
  877.                /* create new exception setup */
  878.                pb->pb_Server->pr_Task.tc_ExceptCode = (APTR)&exceptcode;
  879.                pb->pb_Server->pr_Task.tc_ExceptData = (APTR)pb;
  880.                SetSignal(0, sigmask = (1 << pb->pb_TimeoutPort->mp_SigBit));
  881.                SetExcept(sigmask, sigmask);
  882.  
  883.                /* enter port address */
  884.                pb->pb_CollReq.tr_node.io_Message.mn_ReplyPort = pb->pb_CollPort;
  885.                if (!OpenDevice("timer.device", UNIT_MICROHZ, (struct IORequest*)&pb->pb_CollReq, 0))
  886.                {
  887.                   TimerBase = (struct Library *)pb->pb_CollReq.tr_node.io_Device;
  888.  
  889.                   /* preset the io command, this will never change */
  890.                   pb->pb_CollReq.tr_node.io_Command = TR_ADDREQUEST;
  891.  
  892.                   /* setup the timeout stuff */
  893.                   pb->pb_TimeoutReq.tr_node.io_Flags = IOF_QUICK;
  894.                   pb->pb_TimeoutReq.tr_node.io_Message.mn_ReplyPort = pb->pb_TimeoutPort;
  895.                   pb->pb_TimeoutReq.tr_node.io_Device = pb->pb_CollReq.tr_node.io_Device;
  896.                   pb->pb_TimeoutReq.tr_node.io_Unit = pb->pb_CollReq.tr_node.io_Unit;
  897.                   pb->pb_TimeoutReq.tr_node.io_Command = TR_ADDREQUEST;
  898.                   pb->pb_TimeoutSet = 0xff;
  899.  
  900.                   readargs(pb);
  901.                   d(("allocating 0x%lx/%ld bytes frame buffer\n",
  902.                                        sizeof(struct PLIPFrame)+pb->pb_MTU,
  903.                                        sizeof(struct PLIPFrame)+pb->pb_MTU));
  904.                   if ((pb->pb_Frame = AllocVec((ULONG)sizeof(struct PLIPFrame) +
  905.                                                   pb->pb_MTU, MEMF_CLEAR|MEMF_ANY)))
  906.                   {
  907.                      rc = TRUE;
  908.                   }
  909.                   else
  910.                   {
  911.                      d(("couldn't allocate frame buffer\n"));
  912.                   }
  913.                }
  914.                else
  915.                {
  916.                   d(("couldn't open timer.device"));
  917.                }
  918.             }
  919.             else
  920.             {
  921.                d(("no port for timeout handling\n"));
  922.             }
  923.          }
  924.          else
  925.          {
  926.             d(("no port for collision handling\n"));
  927.          }
  928.       }
  929.       else
  930.       {
  931.          d(("no server port\n"));
  932.       }
  933.    }
  934.    else
  935.    {
  936.       d(("no signal\n",rc));
  937.    }
  938.  
  939.    d(("left %ld\n",rc));
  940.  
  941.    return rc;
  942. }
  943. /*E*/
  944. /*F*/ PRIVATE VOID cleanup(BASEPTR)
  945. {
  946.    struct BufferManagement *bm;
  947.  
  948.    gooffline(pb);
  949.  
  950.    while(bm = (struct BufferManagement *)RemHead((struct List *)&pb->pb_BufferManagement))
  951.       FreeVec(bm);
  952.  
  953.    if (pb->pb_Frame) FreeVec(pb->pb_Frame);
  954.  
  955.    if (pb->pb_TimeoutPort)
  956.    {
  957.       /* restore old exception setup */
  958.       SetExcept(0, 0xffffffff);    /* turn'em off */
  959.       pb->pb_Server->pr_Task.tc_ExceptCode = pb->pb_OldExceptCode;
  960.       pb->pb_Server->pr_Task.tc_ExceptData = pb->pb_OldExceptData;
  961.       SetExcept(pb->pb_OldExcept, 0xffffffff);
  962.  
  963.       if (TimerBase)
  964.       {
  965.          WaitIO((struct IORequest*)&pb->pb_TimeoutReq);
  966.          CloseDevice((struct IORequest*)&pb->pb_CollReq);
  967.       }
  968.       DeleteMsgPort(pb->pb_TimeoutPort);
  969.    }
  970.    if (pb->pb_CollPort) DeleteMsgPort(pb->pb_CollPort);
  971.  
  972.    if (pb->pb_ServerPort) DeleteMsgPort(pb->pb_ServerPort);
  973.    if (pb->pb_IntSig != -1) FreeSignal(pb->pb_IntSig);
  974.  
  975.    if (pb->pb_Flags & PLIPF_REPLYSS)
  976.    {
  977.       Forbid();
  978.       ReplyMsg((struct Message*)pb->pb_Startup);
  979.    }
  980. }
  981. /*E*/
  982.  
  983.    /*
  984.    ** entry point, mainloop
  985.    */
  986. /*F*/ PUBLIC VOID SAVEDS ServerTask(void)
  987. {
  988.    BASEPTR;
  989.  
  990.    d(("server running\n"));
  991.  
  992.    if (pb = startup())
  993.    {
  994.          /* if we fail to allocate all resources, this flag reminds cleanup()
  995.          ** to ReplyMsg() the startup message
  996.          */
  997.       pb->pb_Flags |= PLIPF_REPLYSS;
  998.  
  999.       if (init(pb))
  1000.       {
  1001.          ULONG recv, portsigmask, timersigmask, wmask;
  1002.          BOOL running, timerqueued = FALSE;
  1003.  
  1004.          /* Ok, we are fine and will tell this mother personally :-) */
  1005.          pb->pb_Startup->ss_Error = 0;
  1006.          /* don't forget this, or we will have to keep a warm place */
  1007.          /* in our coffin for the system */
  1008.          pb->pb_Flags &= ~PLIPF_REPLYSS;
  1009.          ReplyMsg((struct Message*)pb->pb_Startup);
  1010.  
  1011.          portsigmask  = 1 << pb->pb_ServerPort->mp_SigBit;
  1012.          timersigmask = 1 << pb->pb_CollPort->mp_SigBit;
  1013.       
  1014.          wmask = SIGBREAKF_CTRL_F | SIGBREAKF_CTRL_C | pb->pb_IntSigMask | portsigmask | timersigmask;
  1015.  
  1016.          for(running=TRUE;running;)
  1017.          {
  1018.             d(("wmask is 0x%08lx\n", wmask));
  1019.  
  1020.             if (!(pb->pb_Flags & PLIPF_RECEIVING))
  1021.                recv = Wait(wmask);
  1022.             else
  1023.                SetSignal(0, pb->pb_IntSigMask);
  1024.  
  1025.             /*if (recv & pb->pb_IntSigMask)*/
  1026.             if (pb->pb_Flags & PLIPF_RECEIVING)
  1027.             {
  1028.                d(("received an interrupt\n"));
  1029.                doreadreqs(pb);
  1030.             }
  1031.  
  1032.             if (recv & portsigmask)
  1033.             {
  1034.                d(("SANA-II request(s)\n"));
  1035.                dos2reqs(pb);
  1036.             }
  1037.  
  1038.             if (recv & timersigmask)
  1039.             {
  1040.                /* pop message */
  1041.                AbortIO((struct IORequest*)&pb->pb_CollReq);
  1042.                WaitIO((struct IORequest*)&pb->pb_CollReq);
  1043.                timerqueued = FALSE;
  1044.                d(("timer wakeup\n"));
  1045.             }
  1046.  
  1047.                /* try now to do write requests (if any pending) */
  1048.             if (!timerqueued)
  1049.             {
  1050.                dowritereqs(pb);
  1051.  
  1052.                   /* don't let the other side wait too long! */
  1053.                if (pb->pb_Flags & PLIPF_RECEIVING)
  1054.                {
  1055.                   d(("received an interrupt\n"));
  1056.                   SetSignal(0, pb->pb_IntSigMask);
  1057.                   doreadreqs(pb);
  1058.                }
  1059.  
  1060.                /*
  1061.                ** Possible a collision has occurred, which is indicated by a
  1062.                ** special flag in PLIPBase.
  1063.                **
  1064.                ** Using timer.device we periodically will be waked up. This
  1065.                ** allows us to delay write packets in cases when we cannot get
  1066.                ** the line immediately.
  1067.                **
  1068.                ** If client and server are very close together, regarding the point
  1069.                ** of performance, the same delay time could even force multiple
  1070.                ** collisions (at least theoretical, I made no practical tests).
  1071.                ** Probably a CSMA/CD-like random-timed delay would be ideal.
  1072.                */
  1073.                if (pb->pb_Flags & PLIPF_COLLISION)
  1074.                {
  1075.                   pb->pb_Flags &= ~PLIPF_COLLISION;
  1076.                   pb->pb_CollReq.tr_time.tv_secs    = 0;
  1077.                   pb->pb_CollReq.tr_time.tv_micro   = pb->pb_CollisionDelay;
  1078.                   SendIO((struct IORequest*)&pb->pb_CollReq);
  1079.                   timerqueued = TRUE;
  1080.                }
  1081.             }
  1082.  
  1083.             if (recv & SIGBREAKF_CTRL_C)
  1084.             {
  1085.                d(("received break signal\n"));
  1086.                running = FALSE;
  1087.             }
  1088.          }
  1089.  
  1090.          if (timerqueued)
  1091.          {
  1092.                /* finnish pending timer requests */
  1093.             AbortIO((struct IORequest*)&pb->pb_CollReq);
  1094.             WaitIO((struct IORequest*)&pb->pb_CollReq);
  1095.          }
  1096.       }
  1097.       else
  1098.          d(("init() failed\n"));
  1099.  
  1100.       d(("cleaning up\n"));
  1101.       cleanup(pb);
  1102.  
  1103.             /* Exec will enable it's scheduler after we're dead. */
  1104.       Forbid();
  1105.             /* signal mother we're done */
  1106.       if (pb->pb_ServerStoppedSigMask)
  1107.          Signal(pb->pb_Task, pb->pb_ServerStoppedSigMask);
  1108.       pb->pb_Flags |= PLIPF_SERVERSTOPPED;
  1109.    }
  1110.    else
  1111.       d(("no startup packet\n"));
  1112. }
  1113. /*E*/
  1114.  
  1115.